import { Vue, Component } from 'vue-property-decorator';
import http from '@/plugins/http';
import router from '@/router';
import style from './style.module.scss';
import AdminContainer from '@/components/admin-container.vue';
import {
    ConfigOption,
    KBuilderConfig,
} from '@/components/k-builder/types/form';
import {
    FormComponent,
    FormCheckbox,
    FormDate,
    FormInput,
    FormRadio,
    FormSelect, FormImage, FormTextarea, FormMarkdown,
} from '@/components/k-builder/types/form-component';

@Component({
    components: {
        AdminContainer,
        KImageUpload: () => import('@/components/input-upload.vue'),
        KMarkdown: () => import('@/components/markdown/index.vue'),
    }
})
export class KBuilderForm extends Vue {
    private config: KBuilderConfig = {
        autoPlaceholder: true,
    };

    // 表单字段列表
    private items: FormComponent[] = [];

    // 表单数据加载状态
    private formLoading: boolean = false;

    // 表单值
    private formdata: any = {};

    // 验证规则
    private rules: any = {};

    // 表单提交回调
    private submitCallback!: (data: any) => Promise<any>;

    // 表单提交状态
    private subing: boolean = false;

    // 表单完成
    private finished: boolean = false;

    // 设置配置
    protected setConfig(conf: KBuilderConfig) {
        this.config = Object.assign(this.config, conf);

        return this;
    }

    private created() {
        this.build();
        this._dataInit();
    }

    protected build() {}

    private _dataInit() {
        if (typeof this.config.initData == 'string') {
            this.formLoading = true;
            this.$http.get(this.config.initData)
                .finally(() => {
                    this.formLoading = false;
                })
                .then(result => {
                    this.formdata = result.data;
                })
        } else if (this.config.initData) {
            this.config.initData()
                .finally(() => {
                    this.formLoading = false;
                })
                .then(data => {
                    if (data) {
                        this.formdata = data;
                    }
                })
        }
    }

    private addItem(item: FormComponent, setDefaultValue: boolean = true) {

        if (this.config.autoPlaceholder && item.placeholder === undefined) {
            let msg: string = '输入';
            if (!['input', 'textarea', 'editor'].includes(item.__obj__ as string)) {
                msg = '选择';
            }
            item.placeholder = `请${msg}${item.label}`;
        }
        const idx = this.items.push(item);
        if (item.required) {
            this.rules[item.prop] = [
                { required: true, message: `${item.label}不可为空` }
            ];
        }
        if (setDefaultValue && item.defaultValue !== undefined) {
            this.$set(this.formdata, item.prop, item.defaultValue);
        }
        if ((item as any).optionLoad) {
            (item as any).optionLoad().then((result: any) => {
                (item as any).options = result;
                this.items.splice(idx - 1, 1, { ...item })
            })
        }
        return this;
    }

    // 输入框
    protected addInput(data: FormInput) {
        data.__obj__ = 'input';
        this.addItem(data);
        return this;
    }

    // 复选框
    protected addCheckbox(data: FormCheckbox) {
        data.__obj__ = 'checkbox';
        this.addItem(data);
        this.$set(this.formdata, data.prop, []);
        return this;
    }

    // 单选框
    protected addRadio(data: FormRadio) {
        data.__obj__ = 'radio';
        this.addItem(data);
        return this;
    }

    // 下拉框
    protected addSelect(data: FormSelect) {
        data.__obj__ = 'select';
        this.addItem(data);
        return this;
    }

    // 添加日期控件
    protected addDate(data: FormDate) {
        data.__obj__ = 'date';
        this.addItem(data);
        return this;
    }

    // 图片上传
    protected addImage(data: FormImage) {
        data.__obj__ = 'image';
        this.addItem(data);
        return this;
    }

    // 文本域
    protected addTextarea(data: FormTextarea) {
        data.__obj__ = 'textarea';
        this.addItem(data);
        return this;
    }

    // markdown
    protected addMarkdown(data: FormMarkdown) {
        data.__obj__ = 'markdown';
        this.addItem(data);
        return this;
    }

    // 监听提交回调
    protected onSubmit(callback: (data: any) => Promise<any>) {
        this.submitCallback = callback;
        return this;
    }

    // 重置表单
    private onReset() {
        this.formdata = {};
        this.finished = false;
        this.subing = false;
        this._dataInit();
    }

    // 表单提交
    private async eventSubmit(evt: Event) {
        evt.preventDefault();

        if (!this.config.closeValidate) {
            await (this.$refs.form as any).validate()
        }

        if (this.config?.submitUrl) {
            this.subing = true;
            http.post(this.config.submitUrl, this.formdata)
                .finally(() => {
                    this.subing = false;
                })
                .then(() => {
                    this.finished = true;
                })
        }

        if (this.submitCallback != undefined) {
            this.subing = true;
            this.submitCallback(this.formdata)
                .finally(() => {
                    this.subing = false;
                })
                .then(() => {
                    this.finished = true;
                })
        }
    }

    private renderComponent(item: FormComponent) {
        switch (item.__obj__) {
            case 'checkbox':
                return (<el-checkbox-group v-model={this.formdata[item.prop]} placeholder={item.placeholder}>
                    {item.options?.map((opt: ConfigOption) => <el-checkbox label={opt.value}>{opt.label}</el-checkbox>)}
                </el-checkbox-group>)
            case 'radio':
                return (<el-radio-group v-model={this.formdata[item.prop]} placeholder={item.placeholder}>
                    {item.options?.map((opt: ConfigOption) => <el-radio label={opt.value}>{opt.label}</el-radio>)}
                </el-radio-group>)
            case 'select':
                return (<el-select v-model={this.formdata[item.prop]} clearable={true} placeholder={item.placeholder}>
                    {item.options?.map((opt: ConfigOption) => <el-option value={opt.value} label={opt.label}/>)}
                </el-select>)
            case 'date':
                return (<el-date-picker v-model={this.formdata[item.prop]}
                                        type={item.type}
                                        editable={true}
                                        clearable={true}
                                        placeholder={item.placeholder}
                                        start-placeholder={item.startPlaceholder}
                                        end-placeholder={item.endPlaceholder}
                                        format={item.format}
                                        value-format={item.value_format ?? item.format}
                />)
            case 'image':
                return (<k-image-upload v-model={this.formdata[item.prop]} muitl={item.muitl}/>)
            case 'textarea':
                return (<el-input v-model={this.formdata[item.prop]} placeholder={item.placeholder}
                                  type="textarea"
                                  rows={item.rows}/>)
            case 'markdown':
                return (<k-markdown v-model={this.formdata[item.prop]}/>)
            default:
                return <el-input v-model={this.formdata[item.prop]} placeholder={item.placeholder}/>;
        }
    }

    render(h: any) {
        if (this.finished) {
            return <div class={style.formFinished}>


                <i class={['el-icon-circle-check', style.formFinishedIcon]}/>

                <div class={style.formFinishedMsg}>
                    提交完成
                </div>

                <div class={style.formFinishedBtn}>
                    <el-button type="warning" onclick={() => this.onReset()}>继续修改</el-button>

                    <el-button onclick={() => router.back()}>返回上一级</el-button>
                </div>
            </div>;
        }
        return (<admin-container loading={this.formLoading} title={this.config?.title}>
            <el-form ref="form" props={{ model: this.formdata, rules: this.rules, ...this.config }} nativeOn={
                {
                    submit: this.eventSubmit
                }
            }>
                {this.items.filter(e => {
                    if (!e.visibleCondition) {
                        return true;
                    }
                    return e.visibleCondition(this.formdata, e.prop);
                }).map(e => <el-form-item label={e.label} prop={e.prop} label-width={e.labelWidth}>
                    {this.renderComponent(e)}
                </el-form-item>)}

                <el-form-item>
                    <el-button native-type="submit" type="primary" loading={this.subing}>提交</el-button>
                </el-form-item>
            </el-form>
        </admin-container>)
    }
}
